from pyjamas.ui import HTML, RootPanel, HorizontalPanel, VerticalPanel, DockPanel, HTMLPanel, TabPanel, Grid
from pyjamas.ui import SimplePanel, Button, ListBox, Label, HasAlignment, TextBox, Frame
from pyjamas.ui import MenuBar, MenuItem
from pyjamas.ui import DialogBox
from pyjamas.CountryListBox import CountryListBox
from pyjamas.Tooltip import Tooltip, TooltipListener
from pyjamas.AutoComplete import AutoCompleteTextBox
from pyjamas.HTTPRequest import HTTPRequest
from pyjamas.JSONParser import JSONParser
from pyjamas import DOM, Window
from Widgets import SolarCanvas, Calendar, NumericTextBox, DateTextBox

def jsonrs2grid(dic):
    vert = len(dic['rows']) + 1
    horz = 0
    flds = dic['fields']
    rws = dic['rows']
    
    for f in flds:
        if f['isVisible']:
            horz += 1
    
    grid = Grid(vert, horz)
    formatter = grid.getRowFormatter()
    
    horzcounter = 0
    for f in flds:
        if f['isVisible']:
            grid.setHTML(0, horzcounter, "<b>" + f['colRepr'] + "</b>")
            horzcounter += 1

    formatter.addStyleName(0, "tableheader")

    for y in range(1, vert):
        horzcounter = 0
        fieldcounter = 0
        for f in flds:
            if f['isVisible']:    
                grid.setText(y,horzcounter, str(rws[y-1][fieldcounter]))
                horzcounter += 1
            fieldcounter += 1
        if not (y % 2):
            formatter.addStyleName(y, "evenrow")
        formatter.addStyleName(y, "tablebody")

    grid.setStyleName("bordered zebra")

    return grid
    
class CrudPanel(SimplePanel):
    """
    Panel que incorpora la funcionalidad necesaria para altas, bajas y modificaciones de
    registros de una tabla.
    Recibe como parámetros:
    tablename: nombre de la tabla a editar.
    fields: lista de campos.
    fieldsRepr: lista de nombres visibles para los campos.
    listUrl: url a invocar para listado
    editUrl: url a invocar para editar
    insertUrl: url a invocar para insertar un registro.
    deleteUrl: url a invocar para borrar un registro.
    labelAjax: objeto a mostrar/ocultar ante una invocación Ajax.
    Asume: que el primer campo es numérico y es el id de la tabla.
    """

    def __init__(self,
                 tableName = "",
                 fields = None,
                 filterField = None,
                 listUrl = 'list',
                 editUrl = 'edit',
                 insertUrl = 'insert',
                 deleteUrl = 'delete', 
                 labelAjax = None):
        SimplePanel.__init__(self)
        
        if tableName == "":
            self.tableName = "Afiliados"
        else:
            self.tableName = tableName
            
        if fields == None:
            self.fields = [{'colName': 'id', 'colRepr': 'Id', 'isId': True, 'isVisible': False},
            {'colName': 'nombre', 'colRepr': 'Nombre'}]
        else:
            self.fields = fields
        
        self.filterValue = None
        self.filterField = filterField
        if self.filterField:
            for f in self.fields:
                if f['colName'] == self.filterField:
                    self.filterValue = f['colValue']
                    break
                
        self.listUrl = listUrl
        self.editUrl = editUrl
        self.insertUrl = insertUrl
        self.deleteUrl = deleteUrl
        self.lblAjax = labelAjax
        
        self.listFields = None
        self.currentRecord = None
        self.recordList = None
        self.totalAfis = 0
        self.totalPages = 0
        self.currentPage = None
        self.localSortCol = 0
        self.localSortOrder = 1
        
        
        contents = VerticalPanel()
        contents.setSpacing(4)
        contents.setHorizontalAlignment(HasAlignment.ALIGN_CENTER)
        self.lista = SimplePanel() 
        contents.add(self.lista)
        
        pagebar = HorizontalPanel()
        pagebar.setVerticalAlignment(HasAlignment.ALIGN_MIDDLE)
        pagebar.setSpacing(4)
        pagebar.add(Button("&lt;&lt;", getattr(self, "onGoFirst")))
        self.btnPrevious = Button("&lt;", getattr(self, "onGoPrevious"))
        pagebar.add(self.btnPrevious)
        pagebar.add(Label("Pag."))
        self.txtInicio = TextBox()
        self.txtInicio.setVisibleLength(4)
#        self.txtInicio.setMaxLength(2)
        self.txtInicio.setTextAlignment(HasAlignment.ALIGN_RIGHT)
        self.txtInicio.setText("0")
        self.txtInicio.addKeyboardListener(self)
        pagebar.add(self.txtInicio)
        pagebar.add(Label("/"))
        self.lblTotalPages = Label("0")
        pagebar.add(self.lblTotalPages)
        self.btnNext = Button("&gt;", getattr(self, "onGoNext"))
        pagebar.add(self.btnNext)
        pagebar.add(Button("&gt;&gt;", getattr(self, "onGoLast")))
        pagebar.add(Label("  Regs. x Pag:"))
        self.txtCantidad = TextBox()
        self.txtCantidad.setVisibleLength(2)
        self.txtCantidad.setMaxLength(2)
        self.txtCantidad.setTextAlignment(HasAlignment.ALIGN_RIGHT)
        self.txtCantidad.setText("10")
        self.txtCantidad.addKeyboardListener(self)
        pagebar.add(self.txtCantidad)
        pagebar.add(Label(" Ordenar por:"))
        self.cboSortBy = ListBox()
        for i in range(len(self.fields)):
            if self.fields[i]['isVisible']:
                self.cboSortBy.addItem(self.fields[i]['colRepr'], value = self.fields[i]['colName'])
        self.cboSortBy.setVisibleItemCount(0)
        self.cboSortBy.addChangeListener(getattr(self, "requestList"))
        pagebar.add(self.cboSortBy)
        self.cboSortOrder = ListBox()
        self.cboSortOrder.setVisibleItemCount(0)
        self.cboSortOrder.addItem("ASC", value="asc")
        self.cboSortOrder.addItem("DESC", value="desc")
        self.cboSortOrder.addChangeListener(getattr(self, "requestList"))
        pagebar.add(self.cboSortOrder)
        pagebar.setStyleName("bordered")
        contents.add(pagebar)
        
        toolbar = HorizontalPanel()
        toolbar.setSpacing(4)
        toolbar.add(Label("Buscar: "))
        self.txtSearch = TextBox()
        self.txtSearch.setVisibleLength(30)
        self.txtSearch.addKeyboardListener(self)
        toolbar.add(self.txtSearch)
        toolbar.add(Button("Actualizar", getattr(self, "requestList")))
        toolbar.add(Button("Insertar", getattr(self, "onInsert")))
        self.btnEdit = Button("Editar", getattr(self, "onEdit"))
        toolbar.add(self.btnEdit)
        self.btnDelete = Button("Eliminar", getattr(self, "onDelete"))
        toolbar.add(self.btnDelete)
        contents.add(toolbar)
        contents.setStyleName("Contents")
        
        self.setWidget(contents)
    
    def onGoFirst(self):
        self.currentPage = 1
        self.txtInicio.setText(str(self.currentPage))
        self.requestList()
    
    def onGoPrevious(self):
        if self.currentPage > 1:
            self.currentPage -= 1
            self.txtInicio.setText(str(self.currentPage))
            self.requestList()
    
    def onGoNext(self):
        if self.currentPage < self.totalPages:
            self.currentPage += 1
            self.txtInicio.setText(str(self.currentPage))
            self.requestList()
    
    def onGoLast(self):
        self.currentPage = self.totalPages
        self.txtInicio.setText(str(self.currentPage))
        self.requestList()
    
    def _getIdField(self):
        for i in range(len(self.fields)):
            if self.fields[i].get('isId'):
                return i
            return -1
    
    def onInsert(self):
        for i in range(len(self.fields)):
            if self.fields[i]['colName'] == self.filterField:
                self.fields[i]['colValue'] = self.filterValue
            else:
                self.fields[i]['colValue'] = ''

        idField = self._getIdField()
        self.fields[idField]['colValue'] = '0'
                
        frmEdit = FormEditRecord(fields = self.fields, parent = self,
                                 labelAjax = self.lblAjax, onReturn = getattr(self, "requestList"),
                                 onAjax = "onActionResult", url = self.insertUrl, tablename = self.tableName,
                                 filterField = self.filterField, filterValue = self.filterValue)
        frmEdit.setPopupPosition(self.getAbsoluteLeft() + 200,  self.getAbsoluteTop() + 100)
        frmEdit.show()
        
    
    def onEdit(self):
        for i in range(len(self.fields)):
            self.fields[i]['colValue'] = str(self.currentRecord[i])
        
        frmEdit = FormEditRecord(fields = self.fields,
                                 parent = self, labelAjax = self.lblAjax, onReturn = getattr(self, "requestList"),
                                 onAjax = "onActionResult", url = self.editUrl, tablename = self.tableName,
                                 filterField = self.filterField, filterValue = self.filterValue)
        frmEdit.setPopupPosition(self.getAbsoluteLeft() + 150,  self.getAbsoluteTop() + 100)
        frmEdit.show()
        
    def onDelete(self):
        idfield = self._getIdField()
        question = "Seguro desea eliminar el registro %s?" % self.currentRecord[idfield]
        if Window.confirm(question):
            url = self.deleteUrl + "/" + self.currentRecord[idfield] + "?tablename=" + self.tableName
            thisptr = self
            def callback(text):
                thisptr.onActionResult(text)
            HTTPRequest().asyncPost(url, "", JSONLoader(callback, self.lblAjax))
            

    def onActionResult(self, text):
        Window.alert(text)
        self.requestList()

        
    def onCloseDialog(self):
        pass

    def localSort(self, col):
        if col == self.localSortCol:
            if self.localSortOrder == 1:
                self.localSortOrder = -1
            else:
                self.localSortOrder = 1
        else:
            self.localSortCol = col
            self.localSortOrder = 1
        
        rev = False
        if self.localSortOrder < 0:
            rev = True

        def keyfunc(it):
            return it[col + 1]
        
        self.recordList.sort(compareFunc=None, keyFunc=keyfunc, reverse=rev)
        
        newdic = {}
        newdic['fields'] = self.listFields[1:]
        newrows = []
        for r in self.recordList:
            newrows.append(r[1:])
        newdic['rows'] = newrows
        grid = jsonrs2grid(newdic)
        grid.setCellPadding(4)
        grid.setCellSpacing(1)
        grid.addTableListener(self)
        self.lista.setWidget(grid)

    def requestList(self):
        """
        Solicita a la función list" en el servidor pasando los sig. params como parte de la URL:
        1) Donde iniciar el query
        2) Cantidad de registros
        3) Clausula "where" si la hubiere.
        4) Clausula order by.
        
        También envía, vía queryestring:
        
        1) uid: numero arbitrario entre 1 y 1000000 para resolver el problema del cache.
        2) fields: propiedad fields del CrudPanel JSON encoded
        3) tablename: propiedad tablename del objeto CrudPanel
        """
        
        where = ""
        if len(self.filterField):
            where += self.filterField + " = " + self.filterValue + " "
            
        if len(self.txtSearch.getText()):
            if len(where):
                where += " and "
            where += self.cboSortBy.getValue(self.cboSortBy.getSelectedIndex())
            where += "="
            where += self.txtSearch.getText()
        
        order = self.cboSortBy.getValue(self.cboSortBy.getSelectedIndex()) + " "
        order += self.cboSortOrder.getValue(self.cboSortOrder.getSelectedIndex())
        
        params = self.txtInicio.getText() + "/" + self.txtCantidad.getText()
        if where:
            params += "/" + where
        else:
            params += "/1"
            
        params += "/" + order
        
        url = self.listUrl + "/" + params
        data = None
        JS(""" data = parseInt(Math.random() * 1000000); """)
        data = "?uid=" + str(data)
        url += data
        fielddata = "fields=" + JSONParser().encode(self.fields)
        fielddata  += "&tablename=" + self.tableName
        thisptr = self
        def callback(text):
            thisptr.populateList(text)
        HTTPRequest().asyncPost(url, fielddata, JSONLoader(callback, self.lblAjax))

    def populateList(self, text):
        dic = JSONParser().decode(text)
        
        self.recordList = dic['rows']
        self.totalAfis = int(dic['total'])
        self.currentPage = int(dic['page'])
        self.totalPages = int(dic['numpages'])
        
        if self.currentPage == 1:
            self.btnPrevious.setEnabled(False)
        else:
            self.btnPrevious.setEnabled(True)
            
        if self.currentPage == self.totalPages:
            self.btnNext.setEnabled(False)
        else:
            self.btnNext.setEnabled(True)
        
        self.btnEdit.setEnabled(False)
        self.btnDelete.setEnabled(False)
        
        self.txtInicio.setText(str(self.currentPage))
        self.lblTotalPages.setText(str(self.totalPages))
        
        newdic = {}
        newdic['fields'] = self.fields

        newdic['rows'] = self.recordList
        
        grid = jsonrs2grid(newdic)
        grid.setCellPadding(4)
        grid.setCellSpacing(1)
        grid.addTableListener(self)
        self.lista.setWidget(grid)
    
    def onCellClicked(self, grid, row, col):
        if row == 0:
            self.localSort(col)
            return
        
        self.currentRecord = self.recordList[row - 1]
        formatter = grid.getRowFormatter()
        for i in range(1, grid.getRowCount()):
            formatter.removeStyleName(i, "selectedrow")    
        formatter.addStyleName(row, "selectedrow")
        self.btnEdit.setEnabled(True)
        self.btnDelete.setEnabled(True)
        

    def onKeyUp(self, sender, code, modifiers):
        if sender == self.txtInicio or sender == self.txtCantidad:
            if code == 13:
                self.requestList()
        
        if sender == self.txtSearch:
            #searched = self.txtSearch.getText()
            #if len(searched):
                self.requestList()
        
    def onKeyDown(self, sender, code, modifiers):
        pass
    
    def onKeyPress(self, sender, code, modifiers):
        pass


class FormEditRecord(DialogBox):
    def __init__(self, title = "Registro No ", parent = None, 
                 onReturn = None, url = "insert",
                 fields = None, tablename = "", labelAjax = None, onAjax = "onActionResult", autoHide = None,
                 filterField = None, filterValue = None):
        DialogBox.__init__(self, autoHide)
        self.resp = False
        self.fields = fields
        self.filterField = filterField
        self.filterValue = filterValue
        if tablename == "":
            tablename = "Afiliados"
        self.tablename = tablename
        self.parent = parent
        self.onReturn = onReturn
        self.lblAjax = labelAjax
        self.onAjax = onAjax
        self.url = url
        self.id = 0
        
        for f in self.fields:
            if f.get('isId'):
                self.id = int(f['colValue'])
        
        self.mode = "Insert"
        if self.id != 0:
            self.mode = "Update"
        self.setHTML(title + str(self.id) + " - " + self.mode)

        contents = VerticalPanel()
        contents.setSpacing(4)
        
        
        self.grid = Grid(len(self.fields), 2)
        formatter = self.grid.getRowFormatter()
        
        self.boxes = []
        for i in range(len(self.fields)):
            self.grid.setWidget(i, 0, Label(self.fields[i]['colRepr']))
            if self.fields[i].get('colType'):
                colType = self.fields[i]['colType']
                if colType == "numeric":
                    tb = NumericTextBox()
                elif colType == "date":
                    tb = DateTextBox()
                else:
                    tb = TextBox()
            else:    
                tb = TextBox()
            tb.setVisibleLength(50)
            tb.setMaxLength(50)
            if self.fields[i].get('isId'):
                formatter.setVisible(i, False)
            if self.filterField:
                if self.fields[i].get('colName') == self.filterField:
                    formatter.setVisible(i, False)
            tb.setText(self.fields[i]['colValue'])
            self.grid.setWidget(i, 1, tb)
            self.boxes.append(tb)

        contents.add(self.grid)
        
        self.extraPanel = HorizontalPanel()
        self.extraPanel.setSpacing(4)
        self.extraPanel.setVisible(False)
        contents.add(self.extraPanel)
        
        id1 = HTMLPanel.createUniqueId()
        id2 = HTMLPanel.createUniqueId()
        hp = HTMLPanel("<div style='text-align: right;'><span id=" + id2 + "><span id=" + id1 + "></div>")
        hp.setWidth("500px")
        btnOK = Button("  OK  ", getattr(self, "onOK"))
        btnCancel = Button("Cancel", getattr(self, "onCancel"))
        btnOK.setStyleName("toolbarbutton")
        btnCancel.setStyleName("toolbarbutton")
        hp.add(btnOK, id1)
        hp.add(btnCancel, id2)
        contents.add(hp)
        
        self.setWidget(contents)
    
    def onActionResult(self, text):
        Window.alert(text)

    def onOK(self):
        self.resp = True
        params = ""
        
        for i in range(len(self.boxes)):
            self.fields[i]['colValue'] = self.boxes[i].getText()
        
        url = self.url
        params = "fields=" + JSONParser().encode(self.fields)
        params += "&tablename=" + self.tablename
        thisptr = self
        def callback(text):
            thisptr.onActionResult(text)
            
        HTTPRequest().asyncPost(url, params, JSONLoader(callback, self.lblAjax))

        if self.onReturn:
            self.onReturn()

        self.hide()
                     
    def onCancel(self):
        self.hide()

                    
